package progarbre;

import java.util.HashMap;
import java.util.Iterator;
import javax.swing.JTextArea;
import vue.InterpreteurView;

public class ASAProg {

    private static HashMap<Integer, String> annuaireDesFonctions;
    private static HashMap<Integer, ASAFonction> fonctions;
    private static HashMap<Integer, Integer> pile;
    private static int bottom;
    private static int endContext;
    private static int top;
    private boolean isInit = false;

    public ASAProg() {
        annuaireDesFonctions = new HashMap<Integer, String>();
        fonctions = new HashMap<Integer, ASAFonction>();
        bottom = 0;
        endContext = 0;
        top = 0;
    }

    public void initialiser(InterpreteurView view) {
        add("READ", new ASARead(view));
        add("RAND", new ASARand());
        isInit = true;
    }

    public void add(String nomFonction, ASAFonction fonction) {
        if (ASAProg.getFonction(nomFonction, fonction.getNbParametre()) != null) {
            throw new RuntimeException("La fonction " + nomFonction + " avec " + fonction.getNbParametre() + " parametres est déjà déclarer");
        }
        annuaireDesFonctions.put(annuaireDesFonctions.size(), nomFonction);
        fonctions.put(fonctions.size(), fonction);
    }

    public static ASAFonction getFonction(String nomFonction, int nbParametre) {
        ASAFonction fonction = null;
        if (annuaireDesFonctions.containsValue(nomFonction.toUpperCase())) {
            Iterator<Integer> i = annuaireDesFonctions.keySet().iterator();
            while (i.hasNext()) {
                Integer key = i.next();
                if (annuaireDesFonctions.get(key).equals(nomFonction.toUpperCase())) {
                    if (fonctions.get(key).getNbParametre() == nbParametre) {
                        fonction = fonctions.get(key);
                    }
                }
            }
        }
        return fonction;
    }

    public static int push(Integer value) {
        pile.put(top++, value);
        return top - 1;
    }

    public void setView(JTextArea area) {
        for (ASAFonction fonction : fonctions.values()) {
            fonction.setView(area);
        }
    }

    public static int pop() {
        // resout les pop de variable non init (null)
        //
        if (pile.get(--top) == null) {
            pile.put(top, top);
        }
        return pile.remove(top);
    }

    public static Integer get(int pointer) {
        return pile.get(pointer);
    }

    public static void set(int pointer, int value) {
        pile.put(pointer, value);
    }

    public static int getBottom() {
        return bottom;
    }

    public static int getTop() {
        return top;
    }

    public static void setTop(int newTop) {
        top = newTop;
    }

    public static int setBottom(int newBottom) {
        if (newBottom < bottom) {
            top = endContext;
            while (top > newBottom) {
                if (get(top) != null) {
                    top++;
                    break;
                }
                top--;
            }
        }
        else {
            top = newBottom;
        }
        return bottom = newBottom;
    }

    public static int setBottomUnsecure(int newBottom) {
        return bottom = newBottom;
    }

    public static int getEndContext() {
        return endContext;
    }

    public static int setEndContext(int newEndContext) {
        return endContext = newEndContext;
    }

    public ASAFonction sementiqueVerif() {
        if (!isInit) {
            throw new RuntimeException("PAS INIT");
        }
        ASAFonction fonction = getFonction("MAIN", 0);
        if (fonction == null) {
            throw new RuntimeException("No Main");
        }
        return fonction;
    }

    public String notationExplorateur() {
        StringBuilder resultat = new StringBuilder();
        for (ASAFonction fonction : fonctions.values()) {
            if (fonction.getLabelExplorateur().equals("READ") || fonction.getLabelExplorateur().equals("RAND")) {
                continue;
            }
            resultat.append(fonction.notationExplorateur()).append("\n");
        }
        return resultat.toString();
    }

    public void executer() throws Exception {
        ASAFonction fonction = sementiqueVerif();
        pile = new HashMap<Integer, Integer>();
        setEndContext(fonction.getNbDeclare() - 1);
        fonction.interpreter();
        setBottom(0);
        setEndContext(0);
    }
}
